﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace OverlakeApp.ViewModels
{
#if PC
    using AppService = OverlakeWSTester.AppService;
#endif

    /// <summary>
    /// A manager for the calendar information that manages caching and updating of the calendar datastructures.
    /// </summary>
    public class CalendarFactory : ViewModelBase
    {
        /// <summary>
        /// Stores information about a LoadCalendar operation that completed.
        /// </summary>
        public class LoadCalendarCompletedEventArgs : EventArgs
        {
            /// <summary>
            /// The month that was loaded.
            /// </summary>
            public DateTime Month { get; set; }
        }

        private static readonly AppService.OverlakeAppService_1_0SoapClient cl = new AppService.OverlakeAppService_1_0SoapClient();

        /// <summary>
        /// Indicates completion of loading the day rotation calendar.
        /// </summary>
        public event EventHandler<LoadCalendarCompletedEventArgs> LoadCalendarCompleted;

        /// <summary>
        /// IDs of calendar events that we have loaded.
        /// </summary>
        private List<int> IDs { get; set; }

        //private OverlakeViewModel vm { get; set; }

        /// <summary>
        /// The default CalendarFactory constructor.
        /// </summary>
        public CalendarFactory(OverlakeViewModel vm)
        {
            //this.vm = vm;
            this.IDs = new List<int>();
#if PC
            cl.Endpoint.Behaviors.Add(new HttpUserAgentEndpointBehavior());
#endif
            cl.GetCalendarCompleted += cl_GetCalendarCompleted;
            
            //cl.GetDayRotationCalendarCompleted += new EventHandler<AppService.GetDayRotationCalendarCompletedEventArgs>(cl_GetDayRotationCalendarCompleted);
            this.MonthsLoaded = new List<DateTime>();

            foreach (var c in this.CalendarItems)
            {
                this.IDs.Add(c.id);
            }
        }

        void cl_GetCalendarCompleted(object sender, AppService.GetCalendarCompletedEventArgs e)
        {
            IEnumerable<AppService.CalendarEvent> newItems = GetNewCalendarItems(e.Result);

            var newCalendar = new ObservableCollection<AppService.CalendarEvent>();

            foreach (var c in newItems.Concat(CalendarItems))
            {
                newCalendar.Add(c);
            }

            this.CalendarItems = newCalendar;

            if (this.LoadCalendarCompleted != null)
                LoadCalendarCompleted(this, new LoadCalendarCompletedEventArgs { Month = ((DateTime)e.UserState) });
        }


        private IEnumerable<AppService.CalendarEvent> GetNewCalendarItems(IEnumerable<AppService.CalendarEvent> items)
        {
            foreach (var i in items)
            {
                if (!IDs.Contains(i.id))
                {
                    IDs.Add(i.id);
                    yield return i;
                }
            }
        }

        /// <summary>
        /// The list of months that we have loaded, so that we don't reload the same month twice.
        /// </summary>
        public List<DateTime> MonthsLoaded { get; set; }

        /// <summary>
        /// Loads a single month into the calendar.
        /// </summary>
        /// <param name="month">The month of the year to load.  January = 1</param>
        /// <param name="year">The year to load.</param>
        public void LoadMonth(int month, int year)
        {
            DateTime d = DateTime.Parse(year + "-" + month);
            this.LoadMonth(d);
        }

        /// <summary>
        /// Loads a single month into the calendar.
        /// </summary>
        /// <param name="month">The month to load.</param>
        public void LoadMonth(DateTime month)
        {
            if (!MonthsLoaded.Contains(month))
            {
                LoadCalendarEvents(month, month.AddMonths(1), month);
                MonthsLoaded.Add(month);
            }
            else
                if (this.LoadCalendarCompleted != null)
                    LoadCalendarCompleted(this, new LoadCalendarCompletedEventArgs { Month = month });
        }


       /* /// <summary>
        /// Loads calendar events between two dates.
        /// </summary>
        /// <param name="start">The start date.</param>
        /// <param name="end">The end date.</param>
        public void LoadCalendarEvents(DateTime start, DateTime end)
        {
            cl.GetCalendarAsync(start, end);
        }*/

        /// <summary>
        /// Loads calendar events between two dates, with a user state to pass as well.
        /// </summary>
        /// <param name="start">The start date.</param>
        /// <param name="end">The end date.</param>
        /// <param name="state">The user state object.</param>
        public void LoadCalendarEvents(DateTime start, DateTime end, object state)
        {
            cl.GetCalendarAsync(start, end, state);
        }


        /// <summary>
        /// The calendar items that have been loaded.
        /// </summary>
        public ObservableCollection<AppService.CalendarEvent> CalendarItems
        {
            get
            {
                return Settings.GetValueOrDefault("CalendarItems", new ObservableCollection<AppService.CalendarEvent>());
            }
            set
            {
                Settings.AddOrUpdateValue("CalendarItems", value);
                this.OnPropertyChanged("CalendarItems");
            }
        }
    }
}
